package openfalcon

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/nleeper/goment"
)

func DateParse(text string, roundUp bool) (g *goment.Goment, err error) {
	var sMath string

	g, err = goment.New()
	if err != nil {
		return g, fmt.Errorf("Failed to parse date. error: %+v", err)
	}

	if text[0:3] == "now" {
		sMath = text[len("now"):]
	} else {
		// TODO: pos = strings.Index(text, "||")
		sMath = text
	}

	if sMath == "" {
		return g, nil
	}

	return DateMathParse(sMath, g, roundUp)
}

func DateMathParse(sMath string, g *goment.Goment, roundUp bool) (*goment.Goment, error) {
	units := []string{"y", "M", "w", "d", "h", "m", "s"}

	for i := 0; i < len(sMath); {
		var flag, num int
		var unit string
		var err error

		c := string(sMath[i])
		i++

		switch c {
		case "/":
			flag = 0
		case "+":
			flag = 1
		case "-":
			flag = 2
		default:
			return g, fmt.Errorf("Failed to parse datemath. error: (c) %+v", c)
		}

		if isNaN(string(sMath[i])) {
			num = 1
		} else if len(sMath) == 2 {
			num, err = strconv.Atoi(string(sMath[i]))
			if err != nil {
				return g, fmt.Errorf("Failed to parse datemath. error: %+v", err)
			}
		} else {
			iFrom := i
			for !isNaN(string(sMath[i])) {
				i++
				if i > 10 {
					return g, errors.New("Failed to parse datemath. i > 10")
				}
			}

			num, err = strconv.Atoi(sMath[iFrom:i])
			if err != nil {
				return g, fmt.Errorf("Failed to parse datemath. error: %+v", err)
			}
		}

		if flag == 0 {
			// rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
			if num != 1 {
				return g, fmt.Errorf("Failed to parse datemath. error: (flag) %+v (num) %+v", flag, num)
			}
		}

		unit = string(sMath[i])
		i++

		if inArray(unit, units) {
			switch flag {
			case 0:
				if roundUp {
					g.EndOf(unit)
				} else {
					g.StartOf(unit)
				}
			case 1:
				g.Add(num, unit)
			case 2:
				g.Subtract(num, unit)
			}
		} else {
			return g, fmt.Errorf("Failed to parse datemath. error: (unit) %+v", unit)
		}
	}

	return g, nil
}

func isNaN(sNumber string) bool {
	_, err := strconv.Atoi(sNumber)
	if err != nil {
		return true
	}

	return false
}

func inArray(a string, list []string) bool {
	for _, b := range list {
		if b == a {
			return true
		}
	}

	return false
}
